package dataContracts;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.Serializable;


import util.Logger;
import util.SerializationHelper;
import util.ChecksumHelper;

public class SharedFile implements Serializable {
	private static final long serialVersionUID = 2983797087649432267L;
	protected transient File _fileRef;
	protected transient SerializationHelper<FileInfo> _serializer;
	
	public FileInfo fileState;
	public long lastModified;
	// by default, assume it is synchronized
	
	public FileStatus status = FileStatus.Synchronized;
	
	public SharedFile(String filePath) {
		this(new File(filePath));
	}
	
	public SharedFile(File file) {
		fileState = new FileInfo();
		fullPath = file.getPath();
		_fileRef = file;
		lastModified = _fileRef.lastModified();
		_serializer = new SerializationHelper<FileInfo>();
		setName(_fileRef.getName());
		updateChecksum();
	}
	
	public void refresh() {
		if (getFileReference().exists()) {
			// mark if it has changed locally
//			if (!newChecksum.equalsIgnoreCase(getChecksum())) {
//				status = FileStatus.Updated;
				this.lastModified = _fileRef.lastModified();
				this.updateChecksum();
//			}
		} else {
			// mark for deletion
			status = FileStatus.Deleted;
		}
	}
	
	
	//------ SETTERS AND GETTERS FOR METADATA [FileInfo class data]
	//fullpath
	private String fullPath;
	public String getFullPath() {
		return fullPath;
	}
	
	//name
	public String getName() {
		return fileState.name;
	}
	public void setName(String name) {
		fileState.name = name;
	}

	//description
	public String getDescription() {
		return fileState.description;
	}	
	public void setDescription(String description) {
		fileState.description = description;
		attributeUpdated();
	}

	//owner
	public String getOwner() {
		return fileState.owner;
	}
	public void setOwner(String owner) {
		fileState.owner = owner;
		attributeUpdated();
	}
	
	//tags
	public String getTags() {
		return fileState.tags;
	}
	public void setTags(String tags) {
		fileState.tags = tags;
		attributeUpdated();
	}
	
	//comments
	public String getComments() {
		return fileState.comments;
	}
	public void setComments(String comments) {
		fileState.comments = comments;
		attributeUpdated();
	}
	
	//project
	public String getProject() {
		return fileState.project;
	}
	public void setProject(String project) {
		fileState.project = project;
	}
	
	// ------------
	
	// this manages access to the checksum for the actual file contents, stored on the FileState object
	public String getFileChecksum() {
		return fileState.checksum;
	}
	public void updateFileChecksum() {
		if (getFileReference().exists()) {
			//Logger.Debug("Updating checksum from: "+ fileState.checksum + "\t to "+ ChecksumHelper.GetChecksum(getFileReference()));
			fileState.checksum = ChecksumHelper.GetChecksum(getFileReference());
		}
	}
	
	// this is the checksum of the serialized FileState object, not the file on disk
	public String checksum = "";
	public String getChecksum() {
		// now serialize the fileInfo class and get the checksum on the object
		if (_serializer != null && fileState != null) {
			updateChecksum();
		}
		
		return checksum;
	}
	public void updateChecksum() {
		// make sure the fileInfo checksum is accurate
		updateFileChecksum();

		// now serialize the fileInfo class and get the checksum on the object
		if (_serializer != null) {
			ByteArrayInputStream bs = _serializer.toByteInputStream(fileState);
			this.checksum = ChecksumHelper.GetChecksum(bs);
		}
	}

	public boolean isIsLocked() {
		return fileState.isLocked;
	}
	public void Lock() {
		fileState.isLocked = true;
	}
	
	public File getFileReference() {
		return _fileRef;
	}
	public void setFileReference(File file) {
		_fileRef = file;
	}
	
	private void attributeUpdated() {
		this.status = FileStatus.Updated;
	}
	
	public boolean equalOnDisk(SharedFile other) {
		if (this.getFileChecksum().equals(other.getFileChecksum())) {
			return true;
		}
		
		return false;
	}

	@Override public boolean equals(Object o) {
		// if it's an object of different type it's always false
		if (!(o instanceof SharedFile))
			return false;
		
		// cast the object to Rational
		SharedFile other = (SharedFile)o;
		// since the Rational is always reduced we can do this simple compare
		if (this.getChecksum().equalsIgnoreCase(other.getChecksum())) {
			return true;
		}
		
		return false;
	}
	
	// we must override this since we overrode equals above
	@Override public int hashCode() {
		// factor in each field used in the equals method
		return getChecksum().hashCode();
	}
	
	// this is called after attributes are changed in the UI
	public void saveAttributes() {
		updateChecksum();
	}
	
	public void afterDeserialize() {
		_serializer = new SerializationHelper<FileInfo>();
		setFileReference(new File(getFullPath()));
	}

}